package org.trc.traffic.analysis;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.geotools.data.shapefile.shp.ShapefileException;
import org.geotools.feature.SchemaException;
import org.trc.io.DBAccess;
import org.trc.network.Network;
import org.trc.traffic.AggLinkTraffic;

/**
 * 
 * Link_Cluster:(linkid, sTime, eTime, Dur)
 * 
 * @author Administrator
 *
 */

public class STLinkCongestionClustering {
	//输入
	protected float maxLinkDistance;

	protected int maxLinkTimeInterval;
	
	//聚簇结果
	protected Map<String, CongestionCluster> congestionClusterSet;

	//辅助
	protected Network road = null; //(几何、拓扑、线性参照)
	
	protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");	
/*	
	private String roadShapefileURL = "D:\\GISDatabase\\Road\\Wuhan_2010.9\\WuhanMainRoad_3rd_PATHNAME_wuchang6_EPSG32650.shp";

	private String mLinkInfoURL = "D:\\GISDatabase\\Road\\Wuhan_2010.9\\road.txt";*/
	
	private String roadShapefileURL = "E:\\Data\\论文实验\\Road\\WuhanMainRoad_3rd_PATHNAME_wuchang6_EPSG32650.shp";

	private String mLinkInfoURL = "E:\\Data\\论文实验\\Road\\road.txt";
	
	//-------------------------------------聚簇------------------------------------//
	
	//数据初始化 
	public void initial(){		
		try {
			this.road = new Network(roadShapefileURL, true);
			
			this.road.generateLinearNetworkByMultiLink(mLinkInfoURL);
			
		} catch (Exception e) {
			
			e.printStackTrace();
			
		} 					
	}
	
	public void buildCongestionCluster(String linkID,int startHour, int endHour, Date day, float maxDistance, int maxTimeInterval){
        if(road == null)
        	this.initial();
		
		this.maxLinkDistance = maxDistance;
		
		this.maxLinkTimeInterval = maxTimeInterval;
		
		// 初始化
		List<AggLinkTraffic> linkTrafficDataSet = DBAccess.getLinkTrafficByLink(linkID, startHour, endHour, day, 0);
		this.congestionClusterSet = Collections.synchronizedMap(new HashMap<String, CongestionCluster>());
		
		// 分组
		int clusterNum = 1;
		for (int i = 0; i < linkTrafficDataSet.size(); i++) {
			if (linkTrafficDataSet.get(i).clusterID == null) {// 未分组 				
				this.expandCongestionCluster(linkTrafficDataSet.get(i),linkTrafficDataSet, linkID, clusterNum + "_" + dateFormat.format(day));
				clusterNum++;
			}
		}
		
		// 生成 LinkCongestionCluster		
		LinkCongestionCluster congestionCluster = null;
		for (AggLinkTraffic linkTraffic : linkTrafficDataSet) {
			if (!congestionClusterSet.containsKey(linkTraffic.clusterID)) {
				congestionCluster = new LinkCongestionCluster(linkTraffic.clusterID);
				congestionCluster.linkid = linkTraffic.linkID;
				congestionClusterSet.put(linkTraffic.clusterID, congestionCluster);
			}
			congestionCluster = (LinkCongestionCluster)congestionClusterSet.get(linkTraffic.clusterID);
			congestionCluster.add(linkTraffic);
		}
	}
	
	private void expandCongestionCluster(AggLinkTraffic coreLinkTraffic, List<AggLinkTraffic> linkTrafficDataSet, String linkID, String clusterNum) {
		String clusterID = "link_" + linkID + "_" + clusterNum; 
		
		coreLinkTraffic.setClusterID(clusterID);
		
		List<AggLinkTraffic> resultDataSet = this.STRangeQuery(coreLinkTraffic, linkTrafficDataSet);
		
		if(resultDataSet.size() == 0)
			return;
		
		for (AggLinkTraffic trafficLink : resultDataSet) {// 标记簇ID
			if(trafficLink.clusterID == null)
				expandCongestionCluster(trafficLink, linkTrafficDataSet, linkID, clusterNum);
		}
	}
	
	// 时空领域查询
	private List<AggLinkTraffic> STRangeQuery(AggLinkTraffic coreLinkTraffic, List<AggLinkTraffic> linkTrafficDataSet) { // 通过遍历
		Vector<AggLinkTraffic> stRange_List = new Vector<AggLinkTraffic>();
		
		for (AggLinkTraffic linkTraffic : linkTrafficDataSet) {
			if(linkTraffic.equals(coreLinkTraffic))
				continue;
			if (timeWithin(coreLinkTraffic, linkTraffic))
				stRange_List.add(linkTraffic);
		}
		
		return stRange_List;
	}

	//时间距离
	private boolean timeWithin(AggLinkTraffic linkTraffic1, AggLinkTraffic linkTraffic2) {
		int linkTimeStamp1 = linkTraffic1.hour *12 + linkTraffic1.timeInterval;
		int linkTimeStamp2 = linkTraffic2.hour *12 + linkTraffic2.timeInterval;
		
		if (Math.abs(linkTimeStamp1 - linkTimeStamp2) > this.maxLinkTimeInterval) {
			return false;
		} else {
			return true;
		}
	}

	//-------------------------------------获取结果------------------------------------//
	
	public ArrayList <CongestionCluster> getCongestionCluster() {
		return new ArrayList <CongestionCluster> (congestionClusterSet.values());
	}
	
	public ArrayList <CongestionCluster> getVIPCongestionCluster(int minDur) {
		ArrayList <CongestionCluster> vipCongestionClusterList = new ArrayList <CongestionCluster> ();
	
		for(CongestionCluster cc : this.getCongestionCluster()){
			LinkCongestionCluster lcc = (LinkCongestionCluster)cc;
			if(lcc.dur >= minDur)
				vipCongestionClusterList.add(lcc);			
		}
		
		return vipCongestionClusterList;
	}
	
	public static void main(String[] args) throws ShapefileException, IOException, ParseException, SchemaException {
		STLinkCongestionClustering stCongestionCluster = new STLinkCongestionClustering();
		
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");
				
		//45546302837 45546302894
		stCongestionCluster.buildCongestionCluster("45547201708", 8, 8, dateFormat.parse("2009-3-8"), 300, 2); //45546202725 45546202735 45546202502

		// 遍历簇
		ArrayList<CongestionCluster> congestionClusters = stCongestionCluster.getCongestionCluster();
		
		for (CongestionCluster congestionCluster : congestionClusters) {
			LinkCongestionCluster cc = (LinkCongestionCluster)congestionCluster;
			System.out.print("CluterID: " + cc.clusterID + ",");
			System.out.print(" StartTime: " + (cc.startTime -96) + ",");
			System.out.print(" EndtTime: " + (cc.endTime - 96));
			System.out.print(" Dur: " + cc.dur);
			System.out.println();
		}
	}

}
